import { patch } from "./vnode/patch.js";
import Watcher from "./observe/watcher.js";

//a: 生命周期文件
export function mountComponent(vm, el) {
  //0.页面加载之前调用生命周期beforeMount
  callHook(vm, "beforeMount");
  //1 调用两个方法-定义在Vue原型上，原型链上，这样每个vm实例都可以访问
  //  (1) vm._update方法是将vnode变成真实dom   （2）vm._render()方法作用是将render函数转成vnode虚拟dom，返回虚拟dom
  // vm._update(vm._render())
  // 1.2.1 把渲染函数抽成一个函数方便调用
  const updateComponent = () => {
    vm._update(vm._render());
  };

  console.log("先触发new Watcher----1");

  //1.2
  let watcher1 = new Watcher(vm, updateComponent, true, () => {
    console.log("watcher--回调函数");
    callHook(vm, "updated"); //实现生命周期updated功能
  }); //里面会初始化

  //1.3页面加载之后
  callHook(vm, "mounted");
  console.log(watcher1, "watcher1");
}

//b:定义_update方法
export function lifecycleMixin(Vue) {
  Vue.prototype._update = function (vnode) {
    console.log(
      vnode,
      "vnode--这是比如当数据更新了然后得到的新的虚拟dom-然后在定义实现虚拟dom转真实dom的方法",
    );
    let vm = this;
    //调用path方法 首次渲染 path传递的第一个参数是真实dom，后面才是虚拟dom，需要经过diff算法进行 新vnode和旧的vnode的比对
    // vm.$el 真实的dom
    // 需要区分一下 是首次还是更新
    let preVnode = vm._vnode; // 如果是首次 值为null  _vnode来
    if (!preVnode) {
      vm.$el = patch(vm.$el, vnode);
      vm._vnode = vnode; // 不是首次，虚拟dom存在，而且是上次的，也就是老的vnode---保存原来的那一次
    } else {
      // 不是首次
      patch(preVnode, vnode);
    }
  };
}
//TODO  (1)render函数  ==> vnode ==> 真实dom

//c:生命周期调用 callHook(cm,'created')
export function callHook(vm, hook) {
  const handlers = vm.$options[hook];
  console.log(handlers, "生命周期函数实现逻辑");
  if (handlers) {
    //
    for (let i = 0; i < handlers.length; i++) {
      // c.1这里调用生命周期函数比如 created然后改变created内部的this指向当前实例vm
      handlers[i].call(vm);
    }
  }
}
